package zhoug.chart.markers;

import android.content.Context;

import com.github.mikephil.charting.charts.Chart;
import com.github.mikephil.charting.charts.CombinedChart;
import com.github.mikephil.charting.components.MarkerView;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.ChartData;
import com.github.mikephil.charting.data.CombinedData;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.PieData;
import com.github.mikephil.charting.data.PieEntry;
import com.github.mikephil.charting.data.RadarData;
import com.github.mikephil.charting.data.RadarEntry;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet;
import com.github.mikephil.charting.interfaces.datasets.IBarLineScatterCandleBubbleDataSet;
import com.github.mikephil.charting.interfaces.datasets.IDataSet;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import com.github.mikephil.charting.interfaces.datasets.IPieDataSet;
import com.github.mikephil.charting.interfaces.datasets.IRadarDataSet;
import com.github.mikephil.charting.model.GradientColor;
import com.github.mikephil.charting.utils.MPPointF;
import zhoug.chart.Chart2Sdk;
import zhoug.chart.R;
import zhoug.chart.core.MPConstant;
import zhoug.chart.formatters.MPAbsValueFormatter;
import zhoug.chart.utils.MPChartUtils;
import zhoug.logging.Logger;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import androidx.annotation.NonNull;

/**
 * @Author 35574
 * @Date 2020/5/6
 * @Description
 */
@SuppressWarnings("all")
public abstract class MPBaseMarker extends MarkerView {
    private static final String TAG = ">>>BaseMarker";
    protected static final boolean DEBUG = Chart2Sdk.isDebug();
    protected int mAutoCancelMarkerSecond = 3;//单位秒,大于0表示时间到了自动关闭marker
    protected int mDecimalPlace = 2;//小数位数
    protected boolean mFillEnd = false;//小数不足时是否使用0补位
    protected int mPercentDecimalPlace = 2;//占比小数位数
    protected boolean mPercentFillEnd = false;//占比小数是否补位

    protected boolean mShowPercent = false;//是否显示占比
    protected int mMaxLabelLength = 0;//label最长的一个的长度
    protected boolean mAlignmentLabel = true;//label对齐
    protected boolean mAddColonAfterLabel = false;//label后面添加冒号
    /**
     * 过滤marker需要展示的数据
     */
    protected MarkerYDataFilter mMarkerYDataFilter;

    /**
     * 长度等于一个中文字符
     */
    protected static final String BLANK_SPACE_3 = "\u3000";
    private boolean backgroundInit=false;//是否设置了背景

    /**
     * Constructor. Sets up the MarkerView with a custom layout resource.
     *
     * @param context
     * @param layoutResource the layout resource to use for the MarkerView
     */
    public MPBaseMarker(Context context, int layoutResource) {
        super(context, layoutResource);
        initBackground();
    }

    protected void initBackground() {
        if(!backgroundInit){
            backgroundInit=true;
            setBackgroundResource(R.drawable.mpchart_marker_bg);
        }
    }

    protected void clearBackground() {
        backgroundInit=false;
        setBackground(null);
    }


    /**
     * 重新必须在最后调用
     *
     * @param entryForHighlight
     * @param highlight
     */
    @Override
    public void refreshContent(Entry entryForHighlight, Highlight highlight) {
        try {
            MarkerIndex markerIndex = computeIndex(entryForHighlight, highlight);
            if (markerIndex != null) {
                MPMarkerData markerData = onRefreshContent(entryForHighlight, highlight, markerIndex);
                if (markerData != null && MPChartUtils.notEmpty(markerData.getData())) {
                    if (DEBUG) {
                        Logger.d(TAG, "##" + markerData.getXLabel());
                        List<MPMarkerData.YData> data = markerData.getData();
                        for (MPMarkerData.YData item : data) {
                            Logger.d(TAG, "#####" + item);
                        }
                    }
                    if (mMarkerYDataFilter != null && markerData != null) {
                        filterMarkerData(markerData);
                    }
                    onBindView(entryForHighlight, highlight, markerData);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            super.refreshContent(entryForHighlight, highlight);
            //时间到了自动关闭marker
            if (mAutoCancelMarkerSecond > 0) {
                Chart chartView = getChartView();
                if (chartView != null) {
                    //移除上一个任务
                    chartView.removeCallbacks(autoCancelMarkerTask);
                    chartView.postDelayed(autoCancelMarkerTask, mAutoCancelMarkerSecond * 1000);
                }
            }
        }
    }

    protected void filterMarkerData(@NonNull MPMarkerData markerData) {
        List<MPMarkerData.YData> data = markerData.getData();
        if (data != null && !data.isEmpty()) {
            Iterator<MPMarkerData.YData> iterator = data.iterator();
            while (iterator.hasNext()) {
                MPMarkerData.YData next = iterator.next();
                boolean b = mMarkerYDataFilter.onFilter(next);
                if (b) {
                    iterator.remove();
                }
            }
        }
    }

    public abstract void onBindView(Entry entryForHighlight, Highlight highlight, @NonNull MPMarkerData markerData);

    /**
     * 计算出marker数据的下标
     *
     * @param entryForHighlight
     * @param highlight
     * @return
     */
    protected MarkerIndex computeIndex(Entry entryForHighlight, Highlight highlight) {
        Chart<?> chartView = getChartView();
        if (chartView != null && entryForHighlight != null && highlight != null) {
            int dataSetIndex = -1, entryIndex = -1;
            //混合图表
            if (chartView instanceof CombinedChart) {
                CombinedChart combinedChart = (CombinedChart) chartView;
                CombinedData combinedData = combinedChart.getData();
                if (combinedData != null) {
                    IDataSet set = combinedData.getDataSetByHighlight(highlight);
                    if (set != null) {
                        entryIndex = set.getEntryIndex(entryForHighlight);
                    }
                    List<IBarLineScatterCandleBubbleDataSet<? extends Entry>> dataSets = combinedData.getDataSets();
                    if (dataSets != null && dataSets.size() > 0) {
                        dataSetIndex = dataSets.indexOf(set);
                    }
                }
            } else {
                ChartData<? extends IDataSet<? extends Entry>> data = chartView.getData();
                if (data != null) {
                    dataSetIndex = highlight.getDataSetIndex();
                    IDataSet set = data.getDataSetByIndex(dataSetIndex);
                    if (set != null) {
                        entryIndex = set.getEntryIndex(entryForHighlight);
                    }
                }
            }
            if (DEBUG) {
                Logger.d(TAG, "dataSetIndex:" + dataSetIndex + ",entryIndex:" + entryIndex);
            }
            if (dataSetIndex != -1 && entryIndex != -1) {
                return new MarkerIndex(dataSetIndex, entryIndex, highlight.getStackIndex());
            }


        }
        return null;
    }

    /**
     * 根据MarkerIndex创建全部可能显示的数据
     *
     * @param entryForHighlight
     * @param highlight
     * @param markerIndex
     * @return
     */
    protected MPMarkerData onRefreshContent(Entry entryForHighlight, Highlight highlight, @NonNull MarkerIndex markerIndex) {
        MPMarkerData markerData = null;
        int dataSetIndex = markerIndex.getDataSetIndex();
        int entryIndex = markerIndex.getEntryIndex();
        Chart<?> chartView = getChartView();
        ChartData<? extends IDataSet<? extends Entry>> data = chartView.getData();
        if (data instanceof LineData) {
            LineData lineData = (LineData) data;
            String xAxisLabel = getXAxisLabel(chartView.getXAxis().getValueFormatter(), entryForHighlight);
            markerData = new MPMarkerData(xAxisLabel);
            markerData.setData(parseLineData(null, lineData, dataSetIndex, entryIndex));
        } else if (data instanceof BarData) {
            BarData barData = (BarData) data;
            String xAxisLabel = getXAxisLabel(chartView.getXAxis().getValueFormatter(), entryForHighlight);
            markerData = new MPMarkerData(xAxisLabel);
            markerData.setData(parseBarData(null, barData, dataSetIndex, entryIndex));
        } else if (data instanceof CombinedData) {
            CombinedData combinedData = (CombinedData) data;
            List<IBarLineScatterCandleBubbleDataSet<? extends Entry>> dataSets = combinedData.getDataSets();
            String xAxisLabel = getXAxisLabel(chartView.getXAxis().getValueFormatter(), entryForHighlight);
            markerData = new MPMarkerData(xAxisLabel);
            BarData barData = combinedData.getBarData();
            if (barData != null) {
                markerData.addData(parseBarData(combinedData, barData, dataSetIndex, entryIndex));
            }
            LineData lineData = combinedData.getLineData();
            if (lineData != null) {
                markerData.addData(parseLineData(combinedData, lineData, dataSetIndex, entryIndex));
            }
        } else if (data instanceof PieData) {
            PieData pieData = (PieData) data;
            markerData = new MPMarkerData("");
            markerData.setData(parsePieData(pieData, dataSetIndex, entryIndex));
        } else if (data instanceof RadarData) {
            RadarData radarData = (RadarData) data;
            markerData = new MPMarkerData("");
            markerData.setData(parseRadarData(radarData, dataSetIndex, entryIndex));

        }
        if (markerData != null) {
            markerData.setDataSetIndex(dataSetIndex);
            markerData.setEntryIndex(entryIndex);
            markerData.setStackIndex(markerIndex.getStackIndex());
        }
        return markerData;
    }

    /**
     * 柱状图marker
     *
     * @param data
     * @param dataSetIndex
     * @param entryIndex
     * @return
     */
    protected List<MPMarkerData.YData> parseBarData(CombinedData combinedData, BarData data, int dataSetIndex, int entryIndex) {
        if (data != null && data.getDataSets() != null) {
            List<IBarDataSet> dataSets = data.getDataSets();
            List<MPMarkerData.YData> list = new ArrayList<>();
            float sum = 0;
            for (int index = 0; index < dataSets.size(); index++) {
                IBarDataSet dataSet = dataSets.get(index);
                if (dataSet != null) {
                    BarEntry entry = dataSet.getEntryForIndex(entryIndex);
                    float[] yVals = entry.getYVals();
                    if (yVals != null && yVals.length > 0) {
                        for (int i = 0; i < yVals.length; i++) {
                            float y = yVals[i];
                            sum += y;
                            MPMarkerData.YData yData = new MPMarkerData.YData();
                            yData.setChartType(MPConstant.BAR_CHART);
                            if (combinedData != null) {
                                yData.setDataSetIndex(MPChartUtils.getDataSetIndex(combinedData, dataSet));
                            } else {
                                yData.setDataSetIndex(index);
                            }
                            String[] stackLabels = dataSet.getStackLabels();
                            if (stackLabels != null && stackLabels.length > 0) {
                                yData.setLabel(stackLabels[i % stackLabels.length]);
                            } else {
                                yData.setLabel(dataSet.getLabel());
                            }
                            yData.setColor(getDataSetColor(dataSet, i));
                            yData.setEntry(entry);
                            yData.setSelfSum(entry.getY());
                            yData.setSelfRatio(entry.getY() != 0 ? y / entry.getY() : 1.0f);
                            yData.setValue(y);
                            ValueFormatter valueFormatter = dataSet.getValueFormatter();
                            if (valueFormatter != null) {
                                yData.setFormatValue(valueFormatter.getFormattedValue(y));
                            }
                            yData.setStackIndex(i);
                            list.add(yData);
                        }
                    } else {
                        float y = entry.getY();
                        sum += y;
                        MPMarkerData.YData yData = new MPMarkerData.YData();
                        yData.setChartType(MPConstant.BAR_CHART);
                        if (combinedData != null) {
                            yData.setDataSetIndex(MPChartUtils.getDataSetIndex(combinedData, dataSet));
                        } else {
                            yData.setDataSetIndex(index);
                        }
                        yData.setLabel(dataSet.getLabel());
                        yData.setColor(getDataSetColor(dataSet, 0));
                        yData.setEntry(entry);
                        yData.setSelfSum(y);
                        yData.setSelfRatio(1.0f);
                        yData.setValue(y);
                        ValueFormatter valueFormatter = dataSet.getValueFormatter();
                        if (valueFormatter != null) {
                            yData.setFormatValue(valueFormatter.getFormattedValue(y));
                        }
                        list.add(yData);
                    }
                }
            }
            if (sum != 0) {
                for (MPMarkerData.YData item : list) {
                    item.setGroupSum(sum);
                    item.setGroupRatio(item.getValue() / sum);
                }
            }
            return list;
        }
        return null;
    }

    /**
     * 曲线图marker
     *
     * @param data
     * @param dataSetIndex
     * @param entryIndex
     * @return
     */
    protected List<MPMarkerData.YData> parseLineData(CombinedData combinedData, LineData data, int dataSetIndex, int entryIndex) {
        if (data != null && data.getDataSets() != null) {
            List<ILineDataSet> dataSets = data.getDataSets();
            List<MPMarkerData.YData> list = new ArrayList<>();
            float sum = 0;
            for (int index = 0; index < dataSets.size(); index++) {
                ILineDataSet dataSet = dataSets.get(index);
                if (dataSet != null) {
                    Entry entry = dataSet.getEntryForIndex(entryIndex);
                    float y = entry.getY();
                    sum += y;
                    MPMarkerData.YData yData = new MPMarkerData.YData();
                    yData.setChartType(MPConstant.LINE_CHART);
                    if (combinedData != null) {
                        yData.setDataSetIndex(MPChartUtils.getDataSetIndex(combinedData, dataSet));
                    } else {
                        yData.setDataSetIndex(index);
                    }
                    yData.setLabel(dataSet.getLabel());
                    yData.setColor(getDataSetColor(dataSet, 0));
                    yData.setEntry(entry);
                    yData.setSelfSum(y);
                    yData.setSelfRatio(1.0f);
                    yData.setValue(y);
                    ValueFormatter valueFormatter = dataSet.getValueFormatter();
                    if (valueFormatter != null) {
                        yData.setFormatValue(valueFormatter.getFormattedValue(y));
                    }
                    list.add(yData);
                }
            }
            if (sum != 0) {
                for (MPMarkerData.YData item : list) {
                    item.setGroupSum(sum);
                    item.setGroupRatio(item.getValue() / sum);
                }
            }
            return list;
        }
        return null;
    }

    /**
     * 饼图marker
     *
     * @param data
     * @param dataSetIndex
     * @param entryIndex
     * @return
     */
    protected List<MPMarkerData.YData> parsePieData(PieData data, int dataSetIndex, int entryIndex) {
        if (data != null) {
            List<MPMarkerData.YData> list = new ArrayList<>();
            IPieDataSet dataSet = data.getDataSet();
            final float sum = data.getYValueSum();
            for (int i = 0; i < dataSet.getEntryCount(); i++) {
                PieEntry entry = dataSet.getEntryForIndex(i);
                float y = entry.getY();
                MPMarkerData.YData yData = new MPMarkerData.YData();
                yData.setChartType(MPConstant.PIE_CHART);
                yData.setDataSetIndex(0);
                yData.setLabel(entry.getLabel());
                yData.setColor(getDataSetColor(dataSet, i));
                yData.setEntry(entry);
                yData.setSelfSum(sum);
                yData.setSelfRatio(sum != 0 ? y / sum : 0);
                yData.setGroupSum(yData.getSelfSum());
                yData.setGroupRatio(yData.getSelfRatio());
                yData.setValue(y);
                yData.setEntryIndex(i);
                ValueFormatter valueFormatter = dataSet.getValueFormatter();
                if (valueFormatter != null) {
                    yData.setFormatValue(valueFormatter.getPieLabel(y, entry));
                }
                list.add(yData);
            }
            return list;
        }
        return null;
    }

    /**
     * 雷达图marker
     *
     * @param data
     * @param dataSetIndex
     * @param entryIndex
     * @return
     */
    protected List<MPMarkerData.YData> parseRadarData(RadarData data, int dataSetIndex, int entryIndex) {
        Chart<?> chartView = getChartView();
        if (data != null && chartView != null) {
            List<MPMarkerData.YData> list = new ArrayList<>();
            IRadarDataSet dataSet = data.getDataSetByIndex(dataSetIndex);
            int entryCount = dataSet.getEntryCount();
            float sum = 0;
            for (int i = 0; i < entryCount; i++) {
                RadarEntry entry = dataSet.getEntryForIndex(i);
                sum += entry.getValue();
            }
            ValueFormatter valueFormatter = chartView.getXAxis().getValueFormatter();
            for (int i = 0; i < dataSet.getEntryCount(); i++) {
                RadarEntry entry = dataSet.getEntryForIndex(i);
                float y = entry.getValue();
                MPMarkerData.YData yData = new MPMarkerData.YData();
                yData.setChartType(MPConstant.RADAR_CHART);
                yData.setDataSetIndex(0);
                yData.setLabel(getRadarXAxisLabel(valueFormatter, i));
                yData.setColor(getDataSetColor(dataSet, i));
                yData.setEntry(entry);
                yData.setSelfSum(sum);
                yData.setSelfRatio(sum != 0 ? y / sum : 0);
                yData.setGroupSum(yData.getSelfSum());
                yData.setGroupRatio(yData.getSelfRatio());
                yData.setValue(y);
                yData.setEntryIndex(i);
                ValueFormatter dataValueFormatter = dataSet.getValueFormatter();
                if (dataValueFormatter != null) {
                    yData.setFormatValue(dataValueFormatter.getFormattedValue(y));
                }
                list.add(yData);
            }
            return list;
        }
        return null;

    }

    protected Runnable autoCancelMarkerTask = new Runnable() {
        @Override
        public void run() {
            MPChartUtils.closeMarker(getChartView());
        }
    };


    /**
     * 获取marker显示的y值的格式化数据
     *
     * @param value
     * @return
     */
    protected String getFormattedValue(float value) {
        return MPChartUtils.formatDecimalUp(value, mDecimalPlace, mFillEnd);
    }

    /**
     * 获取百分比数值
     *
     * @param value 0-1
     * @return
     */
    public String getPercentValue(float value) {
        return MPChartUtils.formatDecimalUp(value * 100, mPercentDecimalPlace, mPercentFillEnd);
    }


    protected String getXAxisLabel(ValueFormatter xValueFormatter, Entry entry) {
        if (xValueFormatter == null) return null;
        String axisLabel;
        if (xValueFormatter instanceof MPAbsValueFormatter) {
            axisLabel = ((MPAbsValueFormatter) xValueFormatter).getAxisLabelNotLimitLength(entry.getX(), null);
        } else {
            axisLabel = xValueFormatter.getAxisLabel(entry.getX(), null);
        }
        return axisLabel;
    }

    protected String getRadarXAxisLabel(ValueFormatter xValueFormatter, int index) {
        if (xValueFormatter == null) return null;
        String axisLabel;
        if (xValueFormatter instanceof MPAbsValueFormatter) {
            axisLabel = ((MPAbsValueFormatter) xValueFormatter).getAxisLabelNotLimitLength(index, null);
        } else {
            axisLabel = xValueFormatter.getAxisLabel(index, null);
        }
        return axisLabel;
    }

    /**
     * 获取到颜色
     *
     * @param dataSet
     * @param index
     * @return
     */
    protected int getDataSetColor(IDataSet dataSet, int index) {
        GradientColor gradientColor = dataSet.getGradientColor();
        if (gradientColor != null) {
            return gradientColor.getStartColor();
        }
        List<GradientColor> gradientColors = dataSet.getGradientColors();
        if (gradientColors != null && gradientColors.size() > 0) {
            return dataSet.getGradientColor(index % gradientColors.size()).getStartColor();
        }
        List<Integer> colors = dataSet.getColors();
        if (colors != null && colors.size() > 0) {
            return dataSet.getColor(index % colors.size());
        }
        return dataSet.getColor();
    }


    @Override
    public MPPointF getOffsetForDrawingAtPoint(float posX, float posY) {
        return super.getOffsetForDrawingAtPoint(posX, posY);
    }

    /**
     * 计算最长的label的长度
     *
     * @param data
     */
    protected void calculateMaxLabelLength(List<MPMarkerData.YData> data, String xLabel) {
        mMaxLabelLength = 0;
        if (mAlignmentLabel) {
            if (data != null && data.size() > 0) {
                int max = 0;
                if (xLabel != null) {
                    max = Math.max(max, xLabel.length());
                }
                for (MPMarkerData.YData item : data) {
                    String label = item.getLabel();
                    if (label != null) {
                        max = Math.max(max, label.length());
                    }
                }
                mMaxLabelLength = max;
            }
        }
    }

    /**
     * label长度小于maxLabelLength时最后面补足空格
     *
     * @param label
     * @return
     */
    public String getLabelFormat(String label) {
        if (label != null) {
            if (mAddColonAfterLabel) {
                label = label + ":";
            }
            if (label.length() < mMaxLabelLength) {
                int a = mMaxLabelLength - label.length();
                for (int i = 0; i < a; i++) {
                    label = label + BLANK_SPACE_3;
                }
            }
        }
        return label;
    }

    public int getDecimalPlace() {
        return mDecimalPlace;
    }

    public void setDecimalPlace(int decimalPlace) {
        this.mDecimalPlace = decimalPlace;
    }

    public boolean isFillEnd() {
        return mFillEnd;
    }

    public void setFillEnd(boolean fillEnd) {
        this.mFillEnd = fillEnd;
    }

    public int getAutoCancelMarkerSecond() {
        return mAutoCancelMarkerSecond;
    }

    public void setAutoCancelMarkerSecond(int autoCancelMarkerSecond) {
        this.mAutoCancelMarkerSecond = autoCancelMarkerSecond;
    }


    public void showPercent(boolean showPercent) {
        this.mShowPercent = showPercent;
    }

    public void setPercentDecimalPlace(int percentDecimalPlace) {
        this.mPercentDecimalPlace = percentDecimalPlace;
    }

    public void setPercentFillEnd(boolean percentFillEnd) {
        this.mPercentFillEnd = percentFillEnd;
    }


    public boolean isAlignmentLabel() {
        return mAlignmentLabel;
    }

    /**
     * label对齐
     *
     * @param alignmentLabel
     */
    public void setAlignmentLabel(boolean alignmentLabel) {
        this.mAlignmentLabel = alignmentLabel;
    }

    public boolean isAddColonAfterLabel() {
        return mAddColonAfterLabel;
    }

    /**
     * label后面添加冒号
     *
     * @param addColonAfterLabel
     */
    public void setAddColonAfterLabel(boolean addColonAfterLabel) {
        this.mAddColonAfterLabel = addColonAfterLabel;
    }

    /**
     * 过滤marker需要展示的数据
     *
     * @param markerYDataFilter
     */
    public void setMarkerYDataFilter(MarkerYDataFilter markerYDataFilter) {
        this.mMarkerYDataFilter = markerYDataFilter;
    }

    public static class MarkerIndex {
        protected int dataSetIndex = -1;
        protected int entryIndex = -1;
        protected int stackIndex = -1;


        public MarkerIndex(int dataSetIndex, int entryIndex, int stackIndex) {
            this.dataSetIndex = dataSetIndex;
            this.entryIndex = entryIndex;
            this.stackIndex = stackIndex;
        }

        public int getDataSetIndex() {
            return dataSetIndex;
        }

        public int getEntryIndex() {
            return entryIndex;
        }

        public int getStackIndex() {
            return stackIndex;
        }
    }
}
